/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package library.Configuration;

import java.util.Properties;
import java.io.InputStream;
import java.io.File;

import org.apache.log4j.*;

/**
 * A configuration file can be referenced as an URL (applet mode) or as a file
 * reference (application mode)
 * 
 * This class is the parent class, common to URL-based and file reference-based
 * config file
 * 
 * This class should not be the entry point to read the configuration file
 * 
 * @author JNC
 */
abstract public class Config {
    /**
     * set of configuration values
     */
    private static Properties _properties = null;
    /**
     * The log4j log
     */    
    private static final Logger _logger = Logger.getLogger(Config.class);    
    
    /**
     * 
     * @param myConfigURL
     */
    /**
     * Reads a configuration value according to the given parameter
     * The configuration value is meant to be a boolean
     * Pragmatically, only value "true" (case insensitive) is meaningful, 
     * any other value  will be interpreted as false
     * @param myKey
     * @return
     */
    public boolean getBooleanProperty(String myKey) {
        
        return (getProperty(myKey).equalsIgnoreCase("true") ? true : false);
    }
    
    /**
     * Reads a configuration value according to the given parameter
     * The configuration value is meant to be a int
     * @param myKey
     * @return
     */
    public int getIntProperty(String myKey) {
        String value = null;
        int ret = 0;
        
        value = getProperty(myKey);
        
        try {
            ret = Integer.parseInt(value);
        }
        catch(NumberFormatException exception) {
            throw new FatalConfigurationException("The config value for key " + myKey + " should be an int but is : " + value + " (exception = " + exception + ")");
        }
        
        return ret;
    }

    /**
     * Reads a configuration value that represents a path or a filename
     * The configuration is meant to be a String
     * The separator char / or \ will be corrected accordingly to the OS
     * @param myKey
     * @return
     */
    public String getPathProperty(String myKey) {
   
        return getProperty(myKey).replace('/', File.separatorChar).replace('\\', File.separatorChar);
    }
    
    /**
     * Reads a configuration value according to the given parameter
     * The configuration value is meant to be a String
     * @param myKey
     * @return
     */
    public String getStringProperty(String myKey) {
        return getProperty(myKey);
    }
    
    /**
     * Open when necessary a configuration file, and reaf the value given by the key
     * @param myKey
     * @return
     */
    private String getProperty(String myKey) {
        String value = null;
        
        // initialization of properties must be done only once
        // ---------------------------------------------------
        if (_properties == null) {
            _logger.debug("This first call initializes the properties");
            initializeProperties();
        }
            
        // tries to get the value of the key
        // ---------------------------------
        value = _properties.getProperty(myKey);
            
        // tests if the key exists
        if (value == null) {
            throw new FatalConfigurationException("The key " + myKey + " does not exist");
        }
        
        // returns the value
        // -----------------
        _logger.debug("Value for the key " + myKey + " = " + value);
        return value;
    }

    /**
     * 
     */
    private void initializeProperties() {
        InputStream file = null;
        
        // try to open the config file
        file = openConfigFile();
            
        // try to get the properties
        try {
            // try to get the properties
            _properties = new Properties();
            _properties.load(file);  
            closeConfigFile(file);
        }
        catch(java.io.IOException exception) {
            _logger.fatal("Error creating the properties (" + exception + ")");
                    
            // reset the _properties to indicate that the configuration 
            // mechanism has not been initialized yet and make still possible
            // some recovery mechanism
             _properties = null;
                   
            // try anyway to close the file
            closeConfigFile(file);       
                    
            throw new FatalConfigurationException("Error creating the properties (" + exception +")");
        }
    }
    
    /**
     * 
     */
    abstract protected InputStream openConfigFile();
    
    /**
     *
     * 
     * @param myFile
     */
    private void closeConfigFile(InputStream myFile) {
        _logger.debug("Try to close the file");
        try {
            myFile.close();
        }
        catch(java.io.IOException exception) {
            _logger.info("Failed trying to close the configuration file - exception : " + exception);
            // nothing to do
        }
    }
}
